"""
配置服务实现类，用于管理应用程序配置
"""
import os
import json
from typing import Dict, Any, Optional

from app.services.config_service import IConfigService
from app.services.base_service import Event
from app.utils.logger import Logger
from app.utils.file_utils import FileUtils
from app.core.default_config import get_default_config


class ConfigService(IConfigService):
    """
    配置服务实现类，用于管理应用程序配置
    """
    
    def __init__(self, config_file_path: str = "data/config.json"):
        """
        初始化配置服务
        
        @param config_file_path: 配置文件路径
        """
        super().__init__()
        self.logger = Logger.get_logger("config_service")
        self.config_file_path = config_file_path
        self._config: Dict[str, Any] = {}
        
        # 添加保存防抖动机制
        self._save_pending = False
        self._last_save_time = 0
        self._save_delay = 0.5  # 延迟保存时间（秒）
        self._config_changed = False  # 标记配置是否有变更
        self._save_timer = None  # 保存定时器
        
        # 加载默认配置
        self._load_default_config()
    
    def _load_default_config(self) -> None:
        """
        加载默认配置
        """
        self._config = get_default_config()
        self.logger.info("已加载默认配置")
    
    def load_config(self) -> bool:
        """
        从文件加载配置
        
        @return: 加载是否成功
        """
        try:
            # 读取配置文件
            config_data = FileUtils.read_json(self.config_file_path)
            
            # 如果配置文件存在且读取成功，则更新配置
            if config_data:
                # 更新配置，但保留默认配置中存在而文件中不存在的项
                self._update_config_recursive(self._config, config_data)
                
                self.logger.info(f"已从文件加载配置：{self.config_file_path}")
                
                # 通知配置已加载
                self.notify(Event("config_loaded", self._config))
                
                return True
            else:
                # 如果配置文件不存在，则保存默认配置到文件
                self.save_config()
                self.logger.info(f"配置文件不存在，已创建默认配置文件：{self.config_file_path}")
                return True
        except Exception as e:
            self.logger.error(f"加载配置失败：{str(e)}")
            return False
    
    def _update_config_recursive(self, target: Dict[str, Any], source: Dict[str, Any]) -> None:
        """
        递归更新配置，保留目标中存在而源中不存在的项
        
        @param target: 目标配置
        @param source: 源配置
        """
        for key, value in source.items():
            if key in target and isinstance(target[key], dict) and isinstance(value, dict):
                # 如果目标和源都是字典，则递归更新
                self._update_config_recursive(target[key], value)
            else:
                # 否则直接更新
                target[key] = value
    
    def _delayed_save(self) -> None:
        """
        延迟保存配置，避免频繁写入文件
        但确保所有配置更改都能被保存
        """
        import time
        current_time = time.time()
        
        # 标记配置已更改
        self._config_changed = True
        
        # 如果已经有待处理的保存，不需要再启动新的定时器
        if self._save_pending:
            return
            
        self._save_pending = True
        
        # 取消之前的定时器（如果存在）
        if self._save_timer and self._save_timer.is_alive():
            # 不能直接取消，但可以让它完成后不执行实际保存
            pass
        
        # 使用定时器延迟保存
        import threading
        self._save_timer = threading.Timer(self._save_delay, self._do_save)
        self._save_timer.daemon = True
        self._save_timer.start()
    
    def _do_save(self) -> None:
        """
        实际执行保存操作
        """
        import time
        try:
            # 检查配置是否有变更
            if not self._config_changed:
                self._save_pending = False
                return
                
            # 确保目录存在
            config_dir = os.path.dirname(self.config_file_path)
            if not os.path.exists(config_dir):
                os.makedirs(config_dir)
            
            # 保存配置到文件，确保使用UTF-8编码
            with open(self.config_file_path, 'w', encoding='utf-8') as f:
                json.dump(self._config, f, ensure_ascii=False, indent=2)
            
            self.logger.info(f"已保存配置到文件：{self.config_file_path}")
            
            # 通知配置已保存
            self.notify(Event("config_saved", self._config))
            
            # 更新最后保存时间
            self._last_save_time = time.time()
            
            # 重置配置变更标记
            self._config_changed = False
        except Exception as e:
            self.logger.error(f"保存配置失败：{str(e)}")
            # 保持配置变更标记为True，以便下次重试
        finally:
            # 重置保存标志
            self._save_pending = False
            
            # 如果配置仍有变更，再次触发保存
            if self._config_changed:
                # 使用短延迟再次尝试保存
                import threading
                retry_timer = threading.Timer(0.1, self._delayed_save)
                retry_timer.daemon = True
                retry_timer.start()
    
    def save_config(self) -> bool:
        """
        保存配置到文件
        
        @return: 保存是否成功
        """
        # 使用延迟保存机制
        self._delayed_save()
        return True
    
    def get(self, key: str, default: Any = None) -> Any:
        """
        获取配置项
        
        @param key: 配置项键名
        @param default: 默认值，如果配置项不存在则返回该值
        @return: 配置项值
        """
        # 支持使用点号分隔的键名，如 "websocket.url"
        if "." in key:
            parts = key.split(".")
            value = self._config
            for part in parts:
                if isinstance(value, dict) and part in value:
                    value = value[part]
                else:
                    return default
            return value
        
        return self._config.get(key, default)
    
    def set(self, key: str, value: Any) -> None:
        """
        设置配置项
        
        @param key: 配置项键名
        @param value: 配置项值
        """
        # 检查值是否发生变化
        old_value = self.get(key)
        if old_value == value:
            # 值未变化，不需要更新
            return
            
        # 支持使用点号分隔的键名，如 "websocket.url"
        if "." in key:
            parts = key.split(".")
            config = self._config
            for i, part in enumerate(parts[:-1]):
                if part not in config:
                    config[part] = {}
                elif not isinstance(config[part], dict):
                    config[part] = {}
                config = config[part]
            config[parts[-1]] = value
        else:
            self._config[key] = value
        
        # 标记配置已更改
        self._config_changed = True
        
        # 通知配置已更改
        self.notify("config_changed", {"key": key, "value": value})
        
        # 对于音色配置，立即保存配置文件
        if key in ["speech.host_voice", "speech.assist_voice"]:
            self.logger.info(f"音色配置已更改: {key}={value}，立即保存配置文件")
            self._do_save()  # 立即保存，不使用延迟机制
    
    def has(self, key: str) -> bool:
        """
        检查配置项是否存在
        
        @param key: 配置项键名
        @return: 是否存在
        """
        # 支持使用点号分隔的键名，如 "websocket.url"
        if "." in key:
            parts = key.split(".")
            value = self._config
            for part in parts:
                if isinstance(value, dict) and part in value:
                    value = value[part]
                else:
                    return False
            return True
        
        return key in self._config
    
    def remove(self, key: str) -> bool:
        """
        移除配置项
        
        @param key: 配置项键名
        @return: 是否成功移除
        """
        # 支持使用点号分隔的键名，如 "websocket.url"
        if "." in key:
            parts = key.split(".")
            config = self._config
            for i, part in enumerate(parts[:-1]):
                if part not in config or not isinstance(config[part], dict):
                    return False
                config = config[part]
            
            if parts[-1] in config:
                del config[parts[-1]]
                # 通知配置已更改
                self.notify("config_changed", {"key": key, "value": None})
                return True
            return False
        
        if key in self._config:
            del self._config[key]
            # 通知配置已更改
            self.notify("config_changed", {"key": key, "value": None})
            return True
        return False
    
    def get_all(self) -> Dict[str, Any]:
        """
        获取所有配置项
        
        @return: 所有配置项
        """
        return self._config.copy()
    
    def get_all_config(self) -> Dict[str, Any]:
        """
        获取所有配置项
        
        @return: 所有配置项
        """
        return self.get_all()
    
    def reset(self) -> None:
        """
        重置配置为默认值
        """
        self._config = self._default_config.copy()
        
        # 通知配置已重置
        self.notify("config_reset", None)
    
    def get_config_file_path(self) -> str:
        """
        获取配置文件路径
        
        @return: 配置文件路径
        """
        return self.config_file_path
        
    def load_config_from_path(self, path: str) -> bool:
        """
        从指定路径加载配置
        
        @param path: 配置文件或目录路径
        @return: 是否成功加载
        """
        try:
            # 如果路径是目录，则在目录中查找 config.json 文件
            if os.path.isdir(path):
                config_file = os.path.join(path, "config.json")
                if not os.path.exists(config_file):
                    self.logger.error(f"指定目录中不存在配置文件: {config_file}")
                    return False
                path = config_file
            
            # 读取配置文件
            if not os.path.exists(path):
                self.logger.error(f"配置文件不存在: {path}")
                return False
                
            config_data = FileUtils.read_json(path)
            if not config_data:
                self.logger.error(f"配置文件为空或格式错误: {path}")
                return False
                
            # 更新配置
            self._config.update(config_data)
            self.logger.info(f"已从路径加载配置: {path}")
            
            # 保存当前配置文件路径
            self.set("app.config_path", os.path.dirname(path) if os.path.isfile(path) else path)
            
            # 触发配置加载事件
            self.emit("config_loaded", self._config)
            
            return True
        except Exception as e:
            self.logger.error(f"从路径加载配置失败: {str(e)}")
            return False
    
    def ensure_saved(self) -> bool:
        """
        确保所有配置更改都已保存
        在应用程序关闭前调用此方法，强制立即保存所有未保存的配置
        
        @return: 保存是否成功
        """
        # 如果没有配置变更，直接返回成功
        if not self._config_changed:
            return True
            
        # 取消可能正在进行的延迟保存
        if self._save_timer and self._save_timer.is_alive():
            try:
                self._save_timer.cancel()
            except:
                pass
            self._save_timer = None
            
        # 重置保存标志
        self._save_pending = False
        
        # 立即执行保存
        try:
            # 确保目录存在
            config_dir = os.path.dirname(self.config_file_path)
            if not os.path.exists(config_dir):
                os.makedirs(config_dir)
            
            # 保存配置到文件
            result = FileUtils.write_json(self.config_file_path, self._config)
            
            if result:
                self.logger.info(f"已强制保存配置到文件：{self.config_file_path}")
                
                # 通知配置已保存
                self.notify(Event("config_saved", self._config))
                
                # 重置配置变更标记
                self._config_changed = False
                
                return True
            else:
                self.logger.error(f"强制保存配置失败：无法写入文件 {self.config_file_path}")
                return False
        except Exception as e:
            self.logger.error(f"强制保存配置失败：{str(e)}")
            return False